package com.company.beauty.common.config;

import com.company.beauty.common.config.properties.OkHttpProperties;
import com.company.beauty.common.constants.BeanConditionalConstants;
import com.company.beauty.common.handler.LoggingRequestInterceptor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;

/**
 * <p>rest</p>
 *
 * @author Lionel Lee
 * @version 1.0: RestTemplateConfig.java
 * @date 2022/6/22 09:38
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(OkHttpProperties.class)
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RestTemplateConfiguration {

    private final OkHttpProperties okHttpProperties;

    public static final String BALANCED_REST_TEMPLATE_BEAN = "BALANCED_REST_TEMPLATE";

    @Primary
    @LoadBalanced
    @Bean(BALANCED_REST_TEMPLATE_BEAN)
    public RestTemplate loadRestTemplate() {
        ClientHttpRequestFactory httpRequestFactory = httpRequestFactory();
        RestTemplate restTemplate = new RestTemplate();
        //通过BufferingClientHttpRequestFactory对象包装现有的ClientHttpRequestFactory，用来支持多次调用getBody()方法
        restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(httpRequestFactory));
        restTemplate.setInterceptors(Collections
                .singletonList(new LoggingRequestInterceptor(okHttpProperties.getConnectTimeout())));
        log.info("基于okhttp的RestTemplate构建完成！");
        return restTemplate;
    }

    /**
     * 工厂
     *
     * @return
     */
    private ClientHttpRequestFactory httpRequestFactory() {
        return new OkHttp3ClientHttpRequestFactory(okHttpConfigClient());
    }

    /**
     * 客户端
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(OkHttpClient.class)
    public OkHttpClient okHttpConfigClient() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return new OkHttpClient().newBuilder().connectionPool(pool())
                .connectTimeout(okHttpProperties.getConnectTimeout(),
                        okHttpProperties.getConnectTimeoutTimeUnit())
                .readTimeout(okHttpProperties.getReadTimeout(),
                        okHttpProperties.getReadTimeoutTimeUnit())
                .writeTimeout(okHttpProperties.getWriteTimeout(),
                        okHttpProperties.getWriteTimeoutTimeUnit())
                .hostnameVerifier((hostname, session) -> true).build();
    }

    /**
     * 连接池
     *
     * @return
     */
    private ConnectionPool pool() {
        return new ConnectionPool(okHttpProperties.getMaxIdleConnections(),
                okHttpProperties.getKeepAliveDuration(),
                okHttpProperties.getKeepAliveDurationTimeUnit());
    }
}
